﻿// Shader-Based-Image-Processing (SBIP)
// http://code.google.com/p/sbip/
//
// Copyright © Frank Nagl, 2009-2011
// admin@franknagl.de
//
namespace SBIP.Filter.NonSBIP
{    
    using System.Drawing;
    using System.Drawing.Imaging;
    using Helper;

    /// <summary>
    /// Posterization of a color (24 bpp) image.
    /// </summary>
    /// 
    /// <remarks><para>Posterization of an image entails conversion of a 
    /// continuous gradation of tone to several regions of fewer tones, 
    /// with abrupt changes from one tone to another.</para>
    /// <para>Sample usage:</para>
    /// <code>
    /// Bitmap image = new Bitmap("Cathedral.jpg");
    /// // create filter
    /// NSPosterization filter = new NSPosterization();
    /// // optional: configure filter
    /// // ...
    /// image = filter.Process(image);
    /// </code>
    /// 
    /// <para><b>Initial image:</b></para>
    /// <img src="../../Cathedral.jpg" width="500" height="338" />
    /// <para><b>Result image:</b></para>
    /// <img src="../../Posterization.png" width="500" height="338" />
    /// </remarks>
    public class NSPosterization : BaseNonSBIPFilter
    {
        /// <summary>
        /// /// Posterization threshold. Default: 90.
        /// </summary>
        public byte Threshold { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="NSPosterization"/> class.
        /// </summary>
        public NSPosterization()
        {
            SupportedSrcPixelFormats = PixelFormatFlags.Color;
            Threshold = 90;
        }

        /// <summary>
        /// Extracts the color segments of the original bitmap as pixel-connected regions.
        /// </summary>
        protected override void Process(BitmapData srcData, BitmapData dstData)
        {
            int pixelSize = Image.GetPixelFormatSize(srcData.PixelFormat) / 8;
            int w = srcData.Width;
            int h = srcData.Height;
            int offset = srcData.Stride - w * pixelSize;

            // process image
            unsafe
            {
                byte* src = (byte*)srcData.Scan0.ToPointer();
                byte* dst = (byte*)dstData.Scan0.ToPointer();
                // for each line
                for (int y = 0; y < h; y++)
                {
                    // for each pixel in line
                    for (int x = 0; x < w; x++, src += pixelSize, dst += pixelSize)
                    {
                        dst[RGBA.R] = (byte)((src[RGBA.R] / Threshold) * Threshold);
                        dst[RGBA.G] = (byte)((src[RGBA.G] / Threshold) * Threshold);
                        dst[RGBA.B] = (byte)((src[RGBA.B] / Threshold) * Threshold);
                        if (pixelSize == 4)
                        {
                            dst[RGBA.A] = src[RGBA.A];
                        }
                        //src[RGB.R] = (byte)(src[RGB.R] ^ threshold);//Bit moving trial
                        //src[RGB.G] = (byte)(src[RGB.G] ^ threshold); //... but to unflexible
                        //src[RGB.B] = (byte)(src[RGB.B] ^ threshold);
                    }
                    src += offset;
                    dst += offset;
                }
            }
        }
    }
}
